from django.conf import settings
from django.shortcuts import render

# Create your views here.
from django.views import View
from django_redis import get_redis_connection
from itsdangerous import TimedJSONWebSignatureSerializer, BadData
from rest_framework import mixins
from rest_framework import status
from rest_framework.decorators import action
from rest_framework.generics import CreateAPIView, RetrieveAPIView, UpdateAPIView, GenericAPIView
from rest_framework.permissions import IsAuthenticated
from rest_framework.response import Response
from rest_framework.views import APIView
from rest_framework.viewsets import GenericViewSet

from goods.models import SKU
from goods.serializers import SKUSerializer
from meiduo import constants
from users import serializers
from users.models import User
from users.serializers import CheckUserSerializer


# class Authorization():
#     """使用系统方法进行用户认证"""
#     # 系统默认校验用户名和密码,为防止出先一个用户将另一个用户的手机号当做用户名进行登录导致异常的情况,
#     # 添加手机号当用户名登录



class UserView(CreateAPIView):
    """注册后端逻辑
    分析:需要接收哪些参数,返回哪些数据给前端?
         name p1 p2 mobile sms_code allow(同意协议)
        参数校验如何进行?
            这些参数在django的用户模型类中大部分都有定义,可不可以使用序列化器进行校验?
        数据如何保存
            序列化器提供了保存功能,并且返回的响应为序列化之后的数据
        需要返回哪些数据给前端?
            id  用户名 手机号
    校验和保存都可以让序列化器帮我们实现  post方法返回sl.data 可以让子类进行实现
    """
    serializer_class = CheckUserSerializer


class UsernameCountView(APIView):
    """ 获取指定用户名的用户数量  如果=0 说明用户名不存在"""

    def get(self, request, username):
        count = User.objects.filter(username=username).count()
        data = {
            "username": username,
            "count": count
        }
        return Response(data)


class MobileCountView(APIView):
    """检测手机号是否存在"""

    def get(self, request, mobile):
        count = User.objects.filter(mobile=mobile).count()
        data = {
            "mobile": mobile,
            "count": count
        }
        return Response(data)


class UserCenterView(RetrieveAPIView):
    """显示登录用户的个人信息
    0.用户已经登录 无需传入pk作为参数查询用户信息
    1.利用drf里的request对象获取user属性
    2.因为继承RetrieveAPIView时  不用再写接口方法  无法利用获取 user
        所以要重写get_object  利用drf的request对象获取user
    """
    serializer_class = serializers.UserDetailSerializer
    permission_classes = [IsAuthenticated]

    def get_object(self):
        return self.request.user


class UserEmailView(UpdateAPIView):
    """获取用户邮箱 进行校验之后 保存到数据库  并发送验证邮件
    """
    permission_classes = [IsAuthenticated]
    serializer_class = serializers.UserEmailSerializer

    def get_object(self):
        return self.request.user


class VerifyEmailView(APIView):
    """验证邮箱,用户点击网址请求页面,取出qs中的token进行校验"""

    def get(self, request):
        token = request.query_params.get('token')
        if not token:
            return Response({"message": "缺少token"})
        # 对token进行解密校验
        user = User.check_email_token(token)

        if user is None:
            # 如果用户不存在
            return Response({"message": "链接信息无效"})
        else:
            # 如果用户存在,将邮箱激活状态置为true
            user.email_active = True
            user.save()
            return Response({"message": "ok"})


class AddressViewSet(mixins.CreateModelMixin, mixins.UpdateModelMixin, GenericViewSet):
    """
    用户地址新增与修改
    """
    serializer_class = serializers.UserAddressSerializer
    permissions = [IsAuthenticated]

    def get_queryset(self):
        return self.request.user.addresses.filter(is_deleted=False)

    # GET /addresses/
    def list(self, request, *args, **kwargs):
        """
        用户地址列表数据
        """
        queryset = self.get_queryset()
        serializer = self.get_serializer(queryset, many=True)
        user = self.request.user
        return Response({
            'user_id': user.id,
            'default_address_id': user.default_address_id,
            'limit': constants.USER_ADDRESS_COUNTS_LIMIT,
            'addresses': serializer.data,
        })

    # POST /addresses/
    def create(self, request, *args, **kwargs):
        """
        保存用户地址数据
        """
        # 检查用户地址数据数目不能超过上限
        count = request.user.addresses.count()
        if count >= constants.USER_ADDRESS_COUNTS_LIMIT:
            return Response({'message': '保存地址数据已达到上限'}, status=status.HTTP_400_BAD_REQUEST)

        return super().create(request, *args, **kwargs)

    # delete /addresses/<pk>/
    def destroy(self, request, *args, **kwargs):
        """
        处理删除
        """
        address = self.get_object()

        # 进行逻辑删除
        address.is_deleted = True
        address.save()

        return Response(status=status.HTTP_204_NO_CONTENT)

    # put /addresses/pk/status/
    @action(methods=['put'], detail=True)
    def status(self, request, pk=None):
        """
        设置默认地址
        """
        address = self.get_object()
        request.user.default_address = address
        request.user.save()
        return Response({'message': 'OK'}, status=status.HTTP_200_OK)

    # put /addresses/pk/title/
    # 需要请求体参数 title
    @action(methods=['put'], detail=True)
    def title(self, request, pk=None):
        """
        修改标题
        """
        address = self.get_object()
        serializer = serializers.AddressTitleSerializer(instance=address, data=request.data)
        serializer.is_valid(raise_exception=True)
        serializer.save()
        return Response(serializer.data)


class UserBrowseHistoryView(CreateAPIView, GenericAPIView):
    """添加和获取用户浏览历史记录"""
    serializer_class = serializers.AddHistorySerialier
    # 限制条件为已经登录认证的用户才会保存历史记录
    permission_classes = [IsAuthenticated]

    def get(self, request):
        """在请求用户个人中心的时候获取用户浏览历史记录  因为需要查询redis和数据库 所以不能使用listapiview
            1.get  redis中根据user_id查询用户浏览的sku_id
            2.通过遍历sku_id列表 从数据库中一条条查询数据 并添加到一个鑫的列表
            3.因为通过query_set查询到的数据是无序的
            """
        user_id = request.user.id
        # 查询redis中的sku_id列表
        redisc = get_redis_connection('history')
        history = redisc.lrange('history_%s' % user_id, 0, constants.USER_HISTORY_COUNT_LIMIT)
        skus = []
        for sku_id in history:
            sku = SKU.objects.get(id=sku_id)
            skus.append(sku)
        sl = SKUSerializer(skus, many=True)
        return Response(sl.data)
